#pragma once
#ifndef CLASS_ACOMB 
#define CLASS_ACOMB 
#include <string> 
#include <iostream>
#include <vector>
#include <algorithm>

#include "TH1.h"
#include "TSystem.h"
#include "TStyle.h"
#include "TCanvas.h"
#include "TChain.h"
#include "TClonesArray.h"
#include "TLorentzVector.h"

#include "ACut.h"
#include "src/Class/AAngle_Self.h"
#include "src/Analyse_Combine/Acomb_func_with_acut.h"

//single cut
class AComb_LTV_Vector_in{
	private:
		int _kind;//how many different kinds of input particles
		std::string   _title;
	public:
		std::vector<TLorentzVector> in1;
		std::vector<TLorentzVector> in2;
		int num1,num2;

	AComb_LTV_Vector_in(){
		_title = "";
		_kind=0;
	}

	AComb_LTV_Vector_in(std::vector<TLorentzVector> &input1, int kind=1){
		_title = "";
		Set(input1, kind);
	}

	AComb_LTV_Vector_in(std::vector<TLorentzVector> &input1, std::vector<TLorentzVector> &input2){
		_title = "";
		Set(input1, input2);
	}

	void Set(std::vector<TLorentzVector> &input1, int kind=1);

	void Set(std::vector<TLorentzVector> &input1, std::vector<TLorentzVector> &input2);

	void Set_Kind(int kind=1);

	void Set_Title(std::string str){
		_title = str;
	}

	void Switch();

	void Add(std::vector<TLorentzVector> &input, int pos);

	void Add(TLorentzVector &input, int pos);

	void Clear();

	std::vector<TLorentzVector> Select_Choosed(int pos1, int pos2);

	int Kind(){
		return(_kind);
	}

	int Num_in1(){
		return(num1);
	}

	int Num_in2(){
		return(num2);
	}

	int Num(){
		return(num1+num2);
	}

	void Print(int level = 2, std::string="");
};


//multi-cuts
class AComb_LTV_Vector_out{
	private:
		int _kind;
		std::string   _title;
	public:
		std::vector<TLorentzVector> out1;
		std::vector<TLorentzVector> out2;
		TLorentzVector comb;
		std::vector<TLorentzVector> left1;
		std::vector<TLorentzVector> left2;
		double                      mt;
		AComb_Angle_Self            angle;
		AComb_DeltaR_Self           deltar;
		AComb_DeltaPhi_Self         deltaphi;
		int                         num_out1,num_out2,num_left1,num_left2;

		std::map<std::string, bool> angle_switch;
	AComb_LTV_Vector_out(){
		_title = "";
	}

	AComb_LTV_Vector_out(std::vector<TLorentzVector> &output1, std::vector<TLorentzVector> &input_left1, int kind=1){
		_title = "";
		Set(output1, input_left1, kind);
	}

	AComb_LTV_Vector_out(std::vector<TLorentzVector> &output1, int num_filled_out1, int kind=1){
		_title = "";
		Set(output1, num_filled_out1, kind);
	}

	AComb_LTV_Vector_out(std::vector<TLorentzVector> &output1, int num_filled_out1, std::vector<TLorentzVector> &output2, int num_filled_out2){
		_title = "";
		Set(output1, num_filled_out1, output2, num_filled_out1);
	}

	AComb_LTV_Vector_out(std::vector<TLorentzVector> &output1, std::vector<TLorentzVector> &output2, std::vector<TLorentzVector> &input_left1, std::vector<TLorentzVector> &input_left2){
		_title = "";
		Set(output1, output2, input_left1, input_left2);
	}

	void Assign_Variables(CDraw &para, AVariable &var);

	void Set(std::vector<TLorentzVector> &output1, std::vector<TLorentzVector> &input_left1, int kind=1);

	void Set(std::vector<TLorentzVector> &output1, std::vector<TLorentzVector> &output2, std::vector<TLorentzVector> &input_left1, std::vector<TLorentzVector> &input_left2);

	void Set(std::vector<TLorentzVector> &output1, int num_filled_out1, int kind=1);

	void Set(std::vector<TLorentzVector> &output1, int num_filled_out1, std::vector<TLorentzVector> &output2, int num_filled_out2);

	void Add(std::vector<TLorentzVector> &output, int kind=1);

	void Add(TLorentzVector &output, int kind=1);

	void Add_Left(std::vector<TLorentzVector> &left, int kind=1);

	void Add_Left(TLorentzVector &left, int kind=1);

	void Add_Comb(TLorentzVector &comb_input);

	void Set_Angle_Switch();

	void Set_Comb();

	void Set_Comb_with_Pos(int pos1=0, int pos2=0);

	TLorentzVector Comb(){
		return(comb);
	}

	double Mt(){
		return(mt);
	}

	void Clear();

	void Set_Kind(int input_kind=1);

	void Switch();

	void Set_Out_with_Pos(int pos1, int pos2, AComb_LTV_Vector_in &in);

	void Set_Left_with_Pos(int pos1, int pos2, AComb_LTV_Vector_in &in);

	void Set_Choosed_with_Pos(int pos1, int pos2, AComb_LTV_Vector_in &in);
	
	int Kind(){
		return(_kind);
	}

	void Set_Title(std::string str){
		_title = str;
	}

	void Set_Angle();

	void Set_DeltaR();

	void Set_DeltaPhi();

	void Set_Distance();

	int Num_out1(){
		return(num_out1);
	}

	int Num_out2(){
		return(num_out2);
	}

	int Num_left1(){
		return(num_left1);
	}

	int Num_left2(){
		return(num_left2);
	}

	int Num(std::string name="");

	void Print(int level = 2, std::string="");

};

class AComb_LTV{
	private:
		bool           _Judge_in;
		bool          _Judge_out;
		bool          _Judge_cut;
		std::string   _title;
	public:
		bool               Judge;
		ACuts               cuts;
		AComb_LTV_Vector_in   in;
		AComb_LTV_Vector_out out;

		AComb_LTV(std::string title=""){
			_title = title;
		}

		AComb_LTV(ACuts &input_cut, std::string title=""){
			_title = title;
			Set_Cut(input_cut);
		};

		AComb_LTV(std::vector<TLorentzVector> &input, int kind=1, std::string title=""){
			_title = title;
			Set_In(input, kind);
		};

		AComb_LTV(std::vector<TLorentzVector> &input_LTV, ACuts &input_cut, int kind=1, std::string title=""){
			_title = title;
			Set_In(input_LTV, input_cut, kind);
		};

		AComb_LTV(std::vector<TLorentzVector> &input1, std::vector<TLorentzVector> &input2, std::string title=""){
			_title = title;
			Set_In(input1, input2);
		};

		AComb_LTV(std::vector<TLorentzVector> &input1, std::vector<TLorentzVector> &input2, ACuts &input_cut, std::string title=""){
			_title = title;
			Set_In(input1, input2, input_cut);
		};

		void Assign_Variables(CDraw &para, AVariable &var){
			out.Assign_Variables(para, var);
		}

		void Set_Title(std::string title="");

		void Set_Cut(ACuts &input_cut);

		void Set_Kind(int input_kind=1);


		void Set_In(std::vector<TLorentzVector> &input, int kind=1);

		void Set_In(std::vector<TLorentzVector> &input, ACuts &input_cut, int kind=1 );

		void Set_In(std::vector<TLorentzVector> &input1, std::vector<TLorentzVector> &input2);

		void Set_In(std::vector<TLorentzVector> &input1, std::vector<TLorentzVector> &input2, ACuts &input_cut);

		void Add_In(std::vector<TLorentzVector> &input, int kind=1);

		void Add_In(TLorentzVector &input, int kind=1);

		void Set_Out(std::vector<TLorentzVector> &output1, std::vector<TLorentzVector> &input_left1, int kind=1 );

		void Set_Out(std::vector<TLorentzVector> &output1, std::vector<TLorentzVector> &output2, std::vector<TLorentzVector> &input_left1, std::vector<TLorentzVector> &input_left2);

		void Set_Out(std::vector<TLorentzVector> &output1, int num_filled_out1, int kind=1 );

		void Set_Out(std::vector<TLorentzVector> &output1, int num_filled_out1, std::vector<TLorentzVector> &output2, int num_filled_out2);
		
		void Add_Out(std::vector<TLorentzVector> &output, int kind=1);

		void Add_Out(TLorentzVector &output, int kind=1);

		void Add_Left(std::vector<TLorentzVector> &left_in, int kind=1);

		void Add_Left(TLorentzVector &left_in, int kind=1);

		void Add_Comb(TLorentzVector &comb);

		void Set(AComb_LTV &input);

		void Set(AComb_LTV &input_acomb, ACuts &input_cuts);

		void Set_Out_with_Pos(int pos1=0, int pos2=0);

		void Set_Comb_with_Pos(int pos1=0, int pos2=0);
		//void Print();

		void Set_Angle();

		void Set_DeltaR();

		void Set_DeltaPhi();

		void Set_Distance();

		void Print(int level = 2, std::string str="");

		void Flow_In_to_Out();

		void Flow_In_to_Left();

		void Transfer_Out(AComb_LTV &input);

		void Transfer_Left(AComb_LTV &input);

		bool Combine_SameFS();

		bool Combine_DifferentFS();

		int Num_In(){
			return(in.Num());
		}

		int Num_Out(){
			return(out.Num());
		}

		int Num(){
			return(in.Num() + out.Num());
		}

		std::string Title();

		std::vector<TLorentzVector> In();
		std::vector<TLorentzVector> In_All();
		std::vector<TLorentzVector> Out();
		std::vector<TLorentzVector> Out_All();
		std::vector<TLorentzVector> Left();
		std::vector<TLorentzVector> Left_All();
		TLorentzVector Comb();
};



#endif
